package com.yiwyn.weakdemo.controller;

import com.yiwyn.weakdemo.domain.User;
import com.yiwyn.weakdemo.utils.FieldCacheKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;
import java.util.WeakHashMap;
import java.util.function.Function;

@Slf4j
@RestController
public class WeakController {

    public static final WeakHashMap<FieldCacheKey, MethodHandle> METHODHANDLE_WEAKHASH_MAP = new WeakHashMap<>();


    private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();

    @GetMapping("/test")
    public String test() throws Throwable {

        long startTime = System.currentTimeMillis();

        for (int i = 0; i < 1000; i++) {

            FieldCacheKey fieldCacheKey = new FieldCacheKey(User.class, "name");
            MethodHandle methodHandle = METHODHANDLE_WEAKHASH_MAP.computeIfAbsent(fieldCacheKey, new Function<FieldCacheKey, MethodHandle>() {
                @Override
                public MethodHandle apply(FieldCacheKey field) {
                    try {
                        Field nameField = field.getClazz().getDeclaredField(field.getFieldName());
                        nameField.setAccessible(true);
                        return LOOKUP.unreflectSetter(nameField);
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    } catch (NoSuchFieldException e) {
                        throw new RuntimeException(e);
                    }
                }
            });

            User user = new User();
            methodHandle.invoke(user, "test" + i);
            log.info("user:{}", user);
        }
        long endTime = System.currentTimeMillis();
        long totalTime = endTime - startTime;
        log.info("total time:{}", totalTime);
        return totalTime + "ms";
    }

    @GetMapping("/look")
    public String look() {
        log.info("weakHashMap:{}", METHODHANDLE_WEAKHASH_MAP);
        return METHODHANDLE_WEAKHASH_MAP.toString();
    }

    @GetMapping("/gc")
    public void gc() {
        System.gc();
    }
}
